package cn.buk.tms.dao;

import cn.buk.common.sc.CommonSearchCriteria;
import cn.buk.common.sc.Page;
import cn.buk.tms.dto.PassengerRecency;
import cn.buk.tms.entity.config.EntAlipayConfig;
import cn.buk.tms.entity.config.EntEotmsConfig;
import cn.buk.tms.entity.config.EnterpriseConfig;
import cn.buk.tms.entity.config.EtermEntConfig;
import cn.buk.tms.sc.SearchCustomerCriteria;
import cn.buk.tms.common.constant.TmsConstant;
import cn.buk.tms.common.constant.TmsOrderConstant;
import cn.buk.common.util.DateUtil;
import cn.buk.tms.entity.misc.*;
import cn.buk.tms.entity.order.flight.FlightOrder;
import jakarta.persistence.criteria.*;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.stereotype.Component;

import jakarta.transaction.Transactional;
import java.text.ParseException;
import java.util.*;

import static cn.buk.common.Constant.DATE_YYYY_MM_DD;
import static cn.buk.tms.common.constant.TmsConstant.ID_TYPE_NI;
import static cn.buk.tms.common.constant.TmsOrderConstant.*;

/**
 * @author yfdai
 */
@Component
@Transactional
public class EnterpriseDaoImpl extends AbstractDao implements EnterpriseDao {

  private static final Logger logger = LogManager.getLogger(EnterpriseDaoImpl.class);

  @Override
  public int create(Enterprise enterprise) {
    em.persist(enterprise);
    return 1;
  }

  @Override
  public Enterprise getEnterpriseById(int id) {
    Enterprise enterprise = em.find(Enterprise.class, id);
    if (enterprise != null) {
      em.refresh(enterprise);
    }

    return enterprise;
  }



  /**
   * 获取付费会员的有效期
   */
  @Override
  public Date getEntExpireDate(int enterpriseId) {
    String val = doGetItemValue(enterpriseId, EnterpriseConfig.ENTERPRISE_EXPIRE_DATE);
    if (val.length() >= 8) {
      try {
        return DateUtil.convertToDate(val, DATE_YYYY_MM_DD);
      } catch (ParseException e) {
        return null;
      }
    } else {
      return null;
    }
  }


  @Override
  public int getBspPrinterNo(int enterpriseId) {
    return getEnterpriseConfig(enterpriseId, EnterpriseConfig.ENTERPRISE_BSP_PRINTER, 1);
  }



  @Override
  public String getEnterpriseConfig(int enterpriseId, String itemCode) {
    return doGetItemValue(enterpriseId, itemCode);
  }

  @Override
  public int getEnterpriseConfig(int enterpriseId, String itemCode, int defaultValue) {
    String retVal = doGetItemValue(enterpriseId, itemCode);
    if (retVal == null || retVal.trim().length() == 0) {
      return defaultValue;
    }

    try {
      return Integer.parseInt(retVal);
    } catch (Exception ex) {
      return defaultValue;
    }
  }

  @Override
  public int setEnterpriseConfig(final int enterpriseId, final String itemCode, final String itemValue) {
    return doSetItemValue(enterpriseId, itemCode, itemValue);
  }


  @Override
  public List<Enterprise> searchEnterprise(CommonSearchCriteria sc) {
    List<Enterprise> results = null;

    CriteriaBuilder cb = em.getCriteriaBuilder();
    CriteriaQuery<Enterprise> cq = cb.createQuery(Enterprise.class);
    Root<Enterprise> root = cq.from(Enterprise.class);

    List<Order> orderByes = new ArrayList<>();
    orderByes.add(cb.desc(root.get("id")));

    cq.orderBy(orderByes);

    //计算根据条件查询得出的数据总数
    CriteriaQuery<Long> countQuery = cb.createQuery(Long.class);
    Root<Enterprise> countRoot = countQuery.from(Enterprise.class);

    countQuery.select(cb.count(countRoot));
    Long count = em.createQuery(countQuery).getSingleResult();

    int maxResults = count.intValue();
    if (maxResults > 0) {
      Page page = sc.getPage();
      page.setRowCount(maxResults);
      int i = (page.getPageNo() - 1) * page.getPageSize();

      if (i < 0) {
        i = 0;
      }

      try {
        results = em.createQuery(cq)
            .setFirstResult(i)
            .setMaxResults(page.getPageSize()).getResultList();

      } catch (Exception ex) {
        ex.printStackTrace();
      }
    }

    if (results == null) {
      results = new ArrayList<>();
    }

    return results;
  }

  /**
   * 开通的国内政策自动比价的监控数量(付费用户)
   */
  @Override
  public int getMonitoredDomPolicyCount(final int enterpriseId) {
    int retVal = 100;
    String val = doGetItemValue(enterpriseId, EnterpriseConfig.ENTERPRISE_DOM_POLICY_MONITOR_COUNT);
    try {
      if (val != null && val.length() > 0) {
        retVal = Integer.parseInt(val);
      }
    } catch (Exception e) {
      logger.error(e.getMessage());
    }

    return retVal;
  }

  @Override
  public int getMonitoredIntlPolicyCount(int enterpriseId) {
    int retVal = 5;

    try {
      String val = doGetItemValue(enterpriseId,
          EnterpriseConfig.ENTERPRISE_INTL_POLICY_MONITOR_COUNT);
      if (val != null && val.length() > 0) {
        retVal = Integer.parseInt(val);
      }
    } catch (Exception e) {
      logger.error(e.getMessage());
    }

    return retVal;
  }

  @Override
  public String getAirlineInCrazyMode(int enterpriseId) {
    return doGetItemValue(enterpriseId, EnterpriseConfig.ENTERPRISE_AIRLINE_IN_CRAZY_MODE);
  }

  @Override
  public EnterpriseBalance getEnterpriseBalance(final int authorizer, final int enterpriseId) {
    return doGetEnterpriseBalance(authorizer, enterpriseId, em);
  }

  /**
   * 获取企业的余额信息
   */
  @Override
  public EnterpriseBalance getEnterpriseBalance(int enterpriseId) {
    return getEnterpriseBalance(Enterprise.ENTERPRISE_PLATFORM_ADMINISTRATOR, enterpriseId);
  }


  /**
   * 查询授权企业的余额信息
   *
   * @param enterpriseId 授权者id
   * @return 企业余额信息列表
   */
  @Override
  public List<EnterpriseBalance> searchMyEntBalance(final int enterpriseId) {
    return em.createQuery("select o from EnterpriseBalance o where o.authorizer = :authorizer order by o.enterpriseId", EnterpriseBalance.class)
        .setParameter("authorizer", enterpriseId)
        .getResultList();
  }

  @Override
  public int updateEntCashBalance(final int enterpriseId, final int opMode, final int modifyAmount0,
      final String remark) {
    int retCode = 0;

    final int modifyAmount = modifyAmount0 * 100;

    EnterpriseBalance entBalance = doGetEnterpriseBalance(enterpriseId, em);

    doUpdateEntBalance(entBalance, opMode, modifyAmount);

    em.merge(entBalance);

    AmountHistory amountHistory = new AmountHistory();
    amountHistory.setEnterpriseId(enterpriseId);
    if (opMode == 0 || opMode == 2) {
      amountHistory.setDebt(modifyAmount);
    } else if (opMode == 1 || opMode == 3) {
      amountHistory.setCredit(modifyAmount);
    }
    amountHistory.setOrderType(100);
    amountHistory.setRemark("系统调整: " + remark);
    amountHistory.setAccountBalance(entBalance.getCashBalance());

    em.persist(amountHistory);

    retCode = 1;

    return retCode;
  }

  private void doUpdateEntBalance(EnterpriseBalance entBalance, int opMode, int modifyAmount) {
    if (opMode == 0) {
      entBalance.decCashBalance(modifyAmount);
    } else if (opMode == 1) {
      entBalance.incCashBalance(modifyAmount);
    } else if (opMode == 2) {//冻结
      entBalance.decCashBalance(modifyAmount);
      entBalance.incFrozenBalance(modifyAmount);
    } else if (opMode == 3) {//解冻
      entBalance.incCashBalance(modifyAmount);
      entBalance.decFrozenBalance(modifyAmount);
    }
  }

  @Override
  public int updateMyEntCashBalance(final int authorizer, final int enterpriseId, final int opMode,
      final int modifyAmount0, final String remark) {
    final int modifyAmount = modifyAmount0 * 100;

    EnterpriseBalance entBalance = doGetEnterpriseBalance(authorizer, enterpriseId, em);

    doUpdateEntBalance(entBalance, opMode, modifyAmount);

    em.merge(entBalance);

    AmountHistory amountHistory = new AmountHistory();
    amountHistory.setEnterpriseId(enterpriseId);
    if (opMode == 0 || opMode == 2) {
      amountHistory.setDebt(modifyAmount);
    } else if (opMode == 1 || opMode == 3) {
      amountHistory.setCredit(modifyAmount);
    }
    amountHistory.setOrderType(100);
    amountHistory.setRemark("系统调整: " + remark);
    amountHistory.setAccountBalance(entBalance.getCashBalance());

    em.persist(amountHistory);

    return 1;
  }

  /**
   * 购买积分
   */
  @Override
  public int buyPoints(final int enterpriseId) {
    int retCode = 0;

    EnterpriseBalance entBalance = doGetEnterpriseBalance(enterpriseId, em);

    int points = entBalance.getCashBalance() % 100;
    if (points == 0) {
      if (entBalance.getCashBalance() >= 10000) {
        points = 10000;
      } else {
        points = entBalance.getCashBalance();
      }
    }

    if (points == 0) {
      retCode = -4;
    } else {

      entBalance.decCashBalance(points);
      em.merge(entBalance);

      entBalance.incBitcoinBalance(points);

      AmountHistory amountHistory = new AmountHistory();
      amountHistory.setEnterpriseId(enterpriseId);
      amountHistory.setCredit(points);
      amountHistory.setOrderType(10);
      amountHistory.setRemark("购买积分: " + points);
      amountHistory.setAccountBalance(entBalance.getBitcoinBalance());
      em.persist(amountHistory);

      amountHistory = new AmountHistory();
      amountHistory.setOrderType(100);
      amountHistory.setEnterpriseId(enterpriseId);
      amountHistory.setDebt(points);
      amountHistory.setRemark("购买积分: " + points);
      amountHistory.setAccountBalance(entBalance.getCashBalance());

      em.merge(entBalance);
      em.persist(amountHistory);

      retCode = points;
    }

    if (retCode <= 0) {
      throw new RuntimeException("购买积分失败：rollback(" + retCode + ")");
    }

    return retCode;
  }

  @Override
  public int createEntCreditLimit(int enterpriseId, int authorizee, int creditLimit) {
    int retCode = 0;

    EnterpriseBalance bal = doGetEnterpriseBalance(enterpriseId, authorizee, em);

    bal.setCreditLimit(creditLimit);

    em.persist(bal);

    retCode = 1;

    return retCode;
  }

  private List<Predicate> buildPredicates_searchCustomerDepartments(CriteriaBuilder cb,
                                                               Root<CustomerDepartment> root,
                                                               int enterpriseId, SearchCustomerCriteria sc) {
    List<Predicate> predicates = new ArrayList<>();

    Predicate predicate = cb.conjunction();
    predicates.add(predicate);

    predicate = cb.equal(root.get(CustomerDepartment_.enterpriseId), enterpriseId);
    predicates.add(predicate);

    if (sc.getName() != null && sc.getName().trim().length() > 0) {
      predicate = cb.like(root.get(CustomerDepartment_.name), "%" + sc.getName() + "%");
      predicates.add(predicate);
    }

    if (sc.getCustomerId() > 0) {
      predicate = cb.equal(root.get(CustomerDepartment_.customer), sc.getCustomerId());
      predicates.add(predicate);
    }

    return predicates;
  }


  @Override
  public List<CustomerDepartment> searchCustomerDepartments(int enterpriseId, SearchCustomerCriteria sc) {
    List<CustomerDepartment> results = null;

    CriteriaBuilder cb = em.getCriteriaBuilder();
    CriteriaQuery<CustomerDepartment> cq = cb.createQuery(CustomerDepartment.class);
    Root<CustomerDepartment> root = cq.from(CustomerDepartment.class);
    root.alias("o");

    var predicates0 = buildPredicates_searchCustomerDepartments(cb, root, enterpriseId, sc);

    //计算根据条件查询得出的数据总数
    CriteriaQuery<Long> countQuery = cb.createQuery(Long.class);
    Root<CustomerDepartment> countRoot = countQuery.from(CustomerDepartment.class);
    countRoot.alias("o");

    var predicates1 = buildPredicates_searchCustomerDepartments(cb, countRoot, enterpriseId, sc);

    // count items
    countQuery.select(cb.count(countRoot))
        .where(predicates1.toArray(new Predicate[0]));
    Long count = em.createQuery(countQuery).getSingleResult();

    //查询
    cq.select(root).where(predicates0.toArray(new Predicate[predicates0.size()]));

    List<Order> orderByes = new ArrayList<>();
    orderByes.add(cb.asc(root.get(CustomerDepartment_.customer).get(Customer_.vipName)));
    orderByes.add(cb.asc(root.get("level")));
    orderByes.add(cb.desc(root.get("name")));

    cq.orderBy(orderByes);

    int maxResults = count.intValue();
    if (maxResults > 0) {
      Page page = sc.getPage();
      page.setRowCount(maxResults);

      try {
        results = em.createQuery(cq)
            .setFirstResult(page.getFirstPosition())
            .setMaxResults(page.getPageSize())
            .getResultList();

      } catch (Exception ex) {
        ex.printStackTrace();
      }
    }

    if (results == null) {
      results = new ArrayList<>();
    }

    return results;
  }

  private List<Predicate> buildPredicates_searchCustomerPositions(CriteriaBuilder cb, Root<CustomerPosition> root, int enterpriseId, SearchCustomerCriteria sc) {

    List<Predicate> predicates = new ArrayList<>();

    Predicate predicate = cb.conjunction();
    predicates.add(predicate);

    predicate = cb.equal(root.get(CustomerPosition_.enterpriseId), enterpriseId);
    predicates.add(predicate);

    if (sc.getName() != null && sc.getName().trim().length() > 0) {
      predicate = cb.like(root.get(CustomerPosition_.name), "%" + sc.getName() + "%");
      predicates.add(predicate);
    }

    return predicates;
  }

  @Override
  public List<CustomerPosition> searchCustomerPositions(int enterpriseId, SearchCustomerCriteria sc) {
    List<CustomerPosition> results = null;

    CriteriaBuilder cb = em.getCriteriaBuilder();
    CriteriaQuery<CustomerPosition> cq = cb.createQuery(CustomerPosition.class);
    Root<CustomerPosition> root = cq.from(CustomerPosition.class);
    root.alias("o");

    var predicates0 = buildPredicates_searchCustomerPositions(cb, root, enterpriseId, sc);

    //计算根据条件查询得出的数据总数
    CriteriaQuery<Long> countQuery = cb.createQuery(Long.class);
    Root<CustomerPosition> countRoot = countQuery.from(CustomerPosition.class);
    countRoot.alias("o");

    var predicates1 = buildPredicates_searchCustomerPositions(cb, countRoot, enterpriseId, sc);

    // count items
    countQuery.select(cb.count(countRoot))
            .where(predicates1.toArray(new Predicate[predicates1.size()]));
    Long count = em.createQuery(countQuery).getSingleResult();

    //查询
    cq.select(root).where(predicates0.toArray(new Predicate[predicates0.size()]));

    List<Order> orderByes = new ArrayList<>();
    orderByes.add(cb.desc(root.get("positionId")));

    cq.orderBy(orderByes);

    int maxResults = count.intValue();
    if (maxResults > 0) {
      Page page = sc.getPage();
      page.setRowCount(maxResults);

      try {
        results = em.createQuery(cq)
                .setFirstResult(page.getFirstPosition())
                .setMaxResults(page.getPageSize())
                .getResultList();

      } catch (Exception ex) {
        ex.printStackTrace();
      }
    }

    if (results == null) {
      results = new ArrayList<>();
    }

    return results;
  }

  @Override
  public List<CustomerPosition> searchCustomerPositions(int enterpriseId, int customerId) {
    return em.createQuery("select o from CustomerPosition o where o.enterpriseId = :enterpriseId and o.customer.id = :customerId", CustomerPosition.class)
            .setParameter("enterpriseId", enterpriseId)
            .setParameter("customerId", customerId)
            .getResultList();
  }

  @Override
  public int saveCustomerDepartment(int enterpriseId, String username, CustomerDepartment department) {
    int retCode = 0;

    department.setEnterpriseId(enterpriseId);

    if (department.getId() == 0) {

      em.persist(department);

      retCode = department.getId();
    } else {
      department.setLastUpdate(DateUtil.getCurDateTime());

      em.merge(department);

      retCode = 1;
    }

    //TODO 日志

    return retCode;
  }

  private List<Predicate> buildPredicates_searchSuppliers(CriteriaBuilder cb, Root<Supplier> root, int enterpriseId, CommonSearchCriteria sc) {

    List<Predicate> predicates = new ArrayList<>();

    Predicate predicate = cb.conjunction();
    predicates.add(predicate);

    predicate = cb.equal(root.get(Supplier_.enterpriseId), enterpriseId);
    predicate = cb.or(predicate, cb.equal(root.get(Supplier_.enterpriseId), 0));
    predicates.add(predicate);

    if (sc.getType() > 0) {
      //特定类型及综合类型
      predicate = cb.equal(root.get(Supplier_.supplierType), 0);
      predicate = cb.or(predicate, cb.equal(root.get(Supplier_.supplierType), sc.getType()));
      predicates.add(predicate);
    } else if (sc.getType() == 0) {
      //综合类型的供应商
      predicate = cb.equal(root.get(Supplier_.supplierType), 0);
      predicates.add(predicate);
    }

    if (sc.getStatus() == 1) {
      // 查找状态为1（启用）的供应商
      predicate = cb.equal(root.get(Supplier_.status), 1);
      predicate = cb.or(predicate, cb.isNull(root.get(Supplier_.status)));
      predicates.add(predicate);
    } else if (sc.getStatus() == 0) {
      // 查找状态为0（未启用）的供应商
      predicate = cb.equal(root.get(Supplier_.status), 0);
      predicates.add(predicate);
    }

    if (StringUtils.isNotBlank(sc.getName())) {
      predicate = cb.like(root.get(Supplier_.name), "%" + sc.getName() + "%");
      predicate = cb.or(predicate, cb.like(root.get(Supplier_.pinyin), "%" + sc.getName() + "%"));
      predicates.add(predicate);
    }

    return predicates;
  }

  @Override
  public List<Supplier> searchSuppliers(int enterpriseId, CommonSearchCriteria sc) {
    List<Supplier> results = null;

    CriteriaBuilder cb = em.getCriteriaBuilder();
    CriteriaQuery<Supplier> cq = cb.createQuery(Supplier.class);
    Root<Supplier> root = cq.from(Supplier.class);
    root.alias("o");

    var predicates0 = buildPredicates_searchSuppliers(cb, root, enterpriseId, sc);



    //计算根据条件查询得出的数据总数
    CriteriaQuery<Long> countQuery = cb.createQuery(Long.class);
    Root<Supplier> countRoot = countQuery.from(Supplier.class);
    countRoot.alias("o");

    var predicates1 = buildPredicates_searchSuppliers(cb, countRoot, enterpriseId, sc);

    // count items
    countQuery.select(cb.count(countRoot))
        .where(predicates1.toArray(new Predicate[0]));
    Long count = em.createQuery(countQuery).getSingleResult();

    //查询
    cq.select(root).where(predicates0.toArray(new Predicate[predicates0.size()]));

    List<Order> orderByes = new ArrayList<>();
    orderByes.add(cb.asc(root.get("enterpriseId")));
    orderByes.add(cb.desc(root.get("status")));
    orderByes.add(cb.desc(root.get("frequency")));
    orderByes.add(cb.asc(root.get("pinyin")));

    cq.orderBy(orderByes);

    int maxResults = count.intValue();
    if (maxResults > 0) {
      Page page = sc.getPage();
      page.setRowCount(maxResults);
      int i = (page.getPageNo() - 1) * page.getPageSize();

      if (i < 0) {
        i = 0;
      }

      try {
        results = em.createQuery(cq)
            .setFirstResult(i)
            .setMaxResults(page.getPageSize()).getResultList();

      } catch (Exception ex) {
        ex.printStackTrace();
      }
    }

    return results == null ? new ArrayList<>() : results;
  }

  @Override
  public List<Supplier> getAllSuppliers(int enterpriseId) {
    return em.createQuery("select o from Supplier o where o.enterpriseId = :enterpriseId order by o.id", Supplier.class)
            .setParameter("enterpriseId", enterpriseId)
            .getResultList();
  }

  @Override
  public int createSupplier(int enterpriseId, Supplier supplier) {
    supplier.setEnterpriseId(enterpriseId);

    em.persist(supplier);

    return supplier.getId();
  }

  @Override
  public int updateSupplier(int enterpriseId, Supplier supplier) {
    Supplier supplier0 = getSupplierById(supplier.getId());
    if (supplier0.getEnterpriseId() != enterpriseId) {
      throw new RuntimeException("Supplier is not existed.");
    }

    supplier0.setName(supplier.getName());
    supplier0.setSupplierType(supplier.getSupplierType());
    supplier0.setRemark(supplier.getRemark());
    supplier0.setPinyin(supplier.getPinyin());
    supplier0.setStatus(supplier.getStatus());
    supplier0.setPaymentMethodId(supplier.getPaymentMethodId());
    supplier0.setLastUpdate(DateUtil.getCurDateTime());

    em.merge(supplier0);

    return supplier.getId();
  }

  private List<Predicate> buildPredicates_searchPaymentMethods(CriteriaBuilder cb, Root<PaymentMethod> root,
                                                               int enterpriseId, CommonSearchCriteria sc) {
    List<Predicate> predicates = new ArrayList<>();

    Predicate predicate = cb.conjunction();
    predicates.add(predicate);

    predicate = cb.equal(root.get(PaymentMethod_.enterpriseId), enterpriseId);
    predicates.add(predicate);

    if (sc.getStatus() == 1) {
      // 查找状态为1（启用）的供应商
      predicate = cb.equal(root.get(PaymentMethod_.status), 1);
      predicate = cb.or(predicate, cb.isNull(root.get(PaymentMethod_.status)));
      predicates.add(predicate);
    } else if (sc.getStatus() == 0) {
      // 查找状态为0（未启用）的供应商
      predicate = cb.equal(root.get(PaymentMethod_.status), 0);
      predicates.add(predicate);
    }

    return predicates;
  }

  @Override
  public List<PaymentMethod> searchPaymentMethods(int enterpriseId, CommonSearchCriteria sc) {
    List<PaymentMethod> results = null;

    CriteriaBuilder cb = em.getCriteriaBuilder();
    CriteriaQuery<PaymentMethod> cq = cb.createQuery(PaymentMethod.class);
    Root<PaymentMethod> root = cq.from(PaymentMethod.class);
    root.alias("o");

    var predicates0 = buildPredicates_searchPaymentMethods(cb, root, enterpriseId, sc);

    //计算根据条件查询得出的数据总数
    CriteriaQuery<Long> countQuery = cb.createQuery(Long.class);
    Root<PaymentMethod> countRoot = countQuery.from(PaymentMethod.class);
    countRoot.alias("o");

    var predicates1 = buildPredicates_searchPaymentMethods(cb, countRoot, enterpriseId, sc);

    // count items
    countQuery.select(cb.count(countRoot))
        .where(predicates1.toArray(new Predicate[predicates1.size()]));
    Long count = em.createQuery(countQuery).getSingleResult();

    //查询
    cq.select(root).where(predicates0.toArray(new Predicate[predicates0.size()]));

    List<Order> orderByes = new ArrayList<>();
    orderByes.add(cb.desc(root.get("status")));
    orderByes.add(cb.asc(root.get("pinyin")));
    orderByes.add(cb.desc(root.get("id")));

    cq.orderBy(orderByes);

    int maxResults = count.intValue();
    if (maxResults > 0) {
      Page page = sc.getPage();
      page.setRowCount(maxResults);
      int i = (page.getPageNo() - 1) * page.getPageSize();

      if (i < 0) {
        i = 0;
      }

      try {
        results = em.createQuery(cq)
            .setFirstResult(i)
            .setMaxResults(page.getPageSize()).getResultList();

      } catch (Exception ex) {
        ex.printStackTrace();
      }
    }

    return results == null ? new ArrayList<>() : results;
  }

  @Override
  public List<IncomeMethod> searchIncomeMethods(int enterpriseId, CommonSearchCriteria sc) {
    List<IncomeMethod> results = null;

    CriteriaBuilder cb = em.getCriteriaBuilder();
    CriteriaQuery<IncomeMethod> cq = cb.createQuery(IncomeMethod.class);
    Root<IncomeMethod> root = cq.from(IncomeMethod.class);
    root.alias("o");

   var predicates0 = getPredicates_searchIncomeMethods(enterpriseId, cb, root);

    //计算根据条件查询得出的数据总数
    CriteriaQuery<Long> countQuery = cb.createQuery(Long.class);
    Root<IncomeMethod> countRoot = countQuery.from(IncomeMethod.class);
    countRoot.alias("o");

    var predicates1 = getPredicates_searchIncomeMethods(enterpriseId, cb, countRoot);

    // count items
    countQuery.select(cb.count(countRoot))
        .where(predicates1.toArray(new Predicate[predicates1.size()]));
    Long count = em.createQuery(countQuery).getSingleResult();

    //查询
    cq.select(root).where(predicates0.toArray(new Predicate[predicates0.size()]));

    List<Order> orderByes = new ArrayList<>();
    orderByes.add(cb.asc(root.get("pinyin")));
    orderByes.add(cb.desc(root.get("id")));

    cq.orderBy(orderByes);

    int maxResults = count.intValue();
    if (maxResults > 0) {
      Page page = sc.getPage();
      page.setRowCount(maxResults);
      int i = (page.getPageNo() - 1) * page.getPageSize();

      if (i < 0) {
        i = 0;
      }

      try {
        results = em.createQuery(cq)
            .setFirstResult(i)
            .setMaxResults(page.getPageSize()).getResultList();

      } catch (Exception ex) {
        ex.printStackTrace();
      }
    }

    if (results == null) {
      results = new ArrayList<>();
    }

    return results;
  }

  private static List<Predicate> getPredicates_searchIncomeMethods(int enterpriseId, CriteriaBuilder cb, Root<IncomeMethod> root) {
    List<Predicate> predicates = new ArrayList<>();

    Predicate predicate = cb.conjunction();
    predicates.add(predicate);

    predicate = cb.equal(root.get(IncomeMethod_.enterpriseId), enterpriseId);
    predicates.add(predicate);
    return predicates;
  }

  @Override
  public int createPaymentMethod(final int enterpriseId, final PaymentMethod info) {
    info.setEnterpriseId(enterpriseId);

    em.persist(info);

    return info.getId();
  }

  @Override
  public int updatePaymentMethod(final int enterpriseId, final PaymentMethod info) {
    PaymentMethod info0 = getPaymentMethodById(info.getId());
    if (info0 == null || info0.getEnterpriseId() != enterpriseId) {
      throw new RuntimeException("PaymentMethod is not existed.");
    }

    info.setLastUpdate(DateUtil.getCurDateTime());

    em.merge(info);

    return info.getId();
  }

  @Override
  public int createIncomeMethod(int enterpriseId, IncomeMethod o) {
    o.setEnterpriseId(enterpriseId);
    em.persist(o);
    return 1;
  }

  @Override
  public int updateIncomeMethod(int enterpriseId, IncomeMethod o) {
    IncomeMethod info = getIncomeMethodById(o.getId());
    if (info == null || info.getEnterpriseId() != enterpriseId) {
      return -1;
    }

    info.setName(o.getName());
    info.setPinyin(o.getPinyin());
    info.setBankName(o.getBankName());
    info.setAccountName(o.getAccountName());
    info.setAccountNo(o.getAccountNo());
    info.setRemark(o.getRemark());
    info.setLastUpdate(DateUtil.getCurDateTime());

    em.merge(info);
    return 1;
  }

  @Override
  public Supplier getSupplierById(int supplierId) {
    return em.find(Supplier.class, supplierId);
  }

  @Override
  public Supplier getSupplierById(int enterpriseId, int id) {
    if (id <= 0) {
      return null;
    }
    Supplier supplier = em.find(Supplier.class, id);

    if (supplier != null && supplier.getEnterpriseId() == enterpriseId) {
      return supplier;
    } else {
      return null;
    }
  }

  /**
   * 获取默认供应商
   */
  @Override
  public Supplier getSupplierByDefault(final int enterpriseId) {
    List<Supplier> suppliers = em.createQuery(
        "select o from Supplier o where o.enterpriseId = :enterpriseId and o.isDefault = 1",
        Supplier.class)
        .setParameter("enterpriseId", enterpriseId)
        .getResultList();
    if (suppliers.isEmpty()) {
      // 没找到默认供应商，再检查系统里是否有供应商，如果没有，那么就新建一个默认供应商，如果只有一个供应商则将它设置为默认供应商
      suppliers = em.createQuery("select o from Supplier o where o.enterpriseId = :enterpriseId",
          Supplier.class)
          .setParameter("enterpriseId", enterpriseId)
          .setMaxResults(5)
          .getResultList();
      if (suppliers.isEmpty()) {
        // 创建
        Supplier supplier = new Supplier();
        supplier.setEnterpriseId(enterpriseId);
        supplier.setName("默认供应商");
        supplier.setSupplierType(0);
        supplier.setIsDefault(1);
        em.persist(supplier);

        return supplier;
      } else if (suppliers.size() == 1) {
        return suppliers.get(0);
      } else {
        return null;
      }
    } else {
      return suppliers.get(0);
    }
  }

  @Override
  public PaymentMethod getPaymentMethodById(int paymentMethodId) {
    return em.find(PaymentMethod.class, paymentMethodId);
  }

  @Override
  public PaymentMethod getPaymentMethodById(int enterpriseId, int id) {
    if (id <= 0) {
      return null;
    }
    PaymentMethod o = em.find(PaymentMethod.class, id);

    if (o == null || o.getEnterpriseId() != enterpriseId) {
      return null;
    } else {
      return o;
    }
  }

  /**
   * 获取默认的支出支付方式
   */
  @Override
  public PaymentMethod getPaymentMethodByDefault(int enterpriseId) {
    List<PaymentMethod> list = em.createQuery(
        "select o from PaymentMethod o where o.enterpriseId = :enterpriseId and o.isDefault = 1",
        PaymentMethod.class)
        .setParameter("enterpriseId", enterpriseId)
        .getResultList();
    if (list.isEmpty()) {
      // 没找到默认供应商，再检查系统里是否有供应商，如果没有，那么就新建一个默认供应商，如果只有一个供应商则将它设置为默认供应商
      list = em.createQuery("select o from PaymentMethod o where o.enterpriseId = :enterpriseId",
          PaymentMethod.class)
          .setParameter("enterpriseId", enterpriseId)
          .setMaxResults(5)
          .getResultList();
      if (list.isEmpty()) {
        // 创建
        PaymentMethod o = new PaymentMethod();
        o.setEnterpriseId(enterpriseId);
        o.setName("默认支出方式");
        o.setIsDefault(1);
        em.persist(o);

        return o;
      } else if (list.size() == 1) {
        return list.get(0);
      } else {
        return null;
      }
    } else {
      return list.get(0);
    }
  }

  @Override
  public IncomeMethod getIncomeMethodById(int id) {

    return em.find(IncomeMethod.class, id);

  }

  @Override
  public List<CustomerDepartment> searchDepartmentsByCustomer(int enterpriseId, int customerId) {
    return em.createQuery(
        "select o from CustomerDepartment o  where o.enterpriseId = :enterpriseId and o.customer.id = :customerId",
        CustomerDepartment.class)
        .setParameter("enterpriseId", enterpriseId)
        .setParameter("customerId", customerId)
        .getResultList();
  }

  @Override
  public List<Groups> searchGroups(int enterpriseId, CommonSearchCriteria sc) {
    return em.createQuery(
        "select o from Groups o  where o.enterpriseId = :enterpriseId order by o.groupName",
        Groups.class)
        .setParameter("enterpriseId", enterpriseId)
        .getResultList();
  }

  @Override
  public int createGroup(Groups o) {
    em.persist(o);
    return 1;
  }

  @Override
  public Groups getGroupInfoById(int id) {

    return em.find(Groups.class, id);

  }

  @Override
  public int updateGroupRole(int enterpriseId, int groupId, String[] roles) {
    int retCode = 0;

    Groups groupInfo = em.find(Groups.class, groupId);
    if (groupInfo == null || groupInfo.getEnterpriseId() != enterpriseId) {
      throw new RuntimeException("Group is not exist.");
    }

    for (String role : roles) {
      GroupRole ga = new GroupRole();
      ga.setGroupInfo(groupInfo);
      ga.setRole(role);

      groupInfo.getAuthorities().add(ga);
    }

    em.merge(groupInfo);

    retCode = 1;

    return retCode;
  }

  @Override
  public int addUserToGroup(int groupId, int userId) {
    int retCode = 0;

    User userInfo = em.find(User.class, userId);
    if (userInfo == null) {
      logger.error("UserIfo is null.");
      throw new RuntimeException("UserInfo is null.");
    }
    Groups groupInfo = em.find(Groups.class, groupId);

    GroupUsers o = new GroupUsers();
    o.setUserInfo(userInfo);
    o.setGroupInfo(groupInfo);

    em.persist(o);

    retCode = o.getId();

    return retCode;
  }

  @Override
  public int deleteUserFromGroup(int groupId, int userId) {
    int retCode = 0;

    retCode = em.createQuery(
        "delete from GroupUsers o where o.groupInfo.id = :groupId and o.userInfo.id = :userId")
        .setParameter("groupId", groupId)
        .setParameter("userId", userId)
        .executeUpdate();

    return retCode;
  }

  @Override
  public List<RoleInfo> searchRoles(int enterpriseId) {
    return em.createQuery("select o from RoleInfo o order by o.role", RoleInfo.class)
        .getResultList();

  }

  @Override
  public List<RolePrivilege> searchRolePrivileges(int enterpriseId, CommonSearchCriteria sc) {
    List<RolePrivilege> results = null;

    CriteriaBuilder cb = em.getCriteriaBuilder();
    CriteriaQuery<RolePrivilege> cq = cb.createQuery(RolePrivilege.class);
    Root<RolePrivilege> root = cq.from(RolePrivilege.class);
    root.alias("o");

    List<Predicate> predicates = new ArrayList<>();

    Predicate predicate = cb.conjunction();
    predicates.add(predicate);

    predicate = cb.equal(root.get(RolePrivilege_.enterpriseId), enterpriseId);
    predicates.add(predicate);

    if (sc.getName() != null && sc.getName().trim().length() > 0) {
      predicate = cb.equal(root.get(RolePrivilege_.role), sc.getName());
      predicates.add(predicate);
    }

    //计算根据条件查询得出的数据总数
    CriteriaQuery<Long> countQuery = cb.createQuery(Long.class);
    Root<RolePrivilege> countRoot = countQuery.from(RolePrivilege.class);
    countRoot.alias("o");

    // count items
    countQuery.select(cb.count(countRoot))
        .where(predicates.toArray(new Predicate[predicates.size()]));
    Long count = em.createQuery(countQuery).getSingleResult();

    //查询
    cq.select(root).where(predicates.toArray(new Predicate[predicates.size()]));

    List<Order> orderByes = new ArrayList<>();
    orderByes.add(cb.asc(root.get("role")));
    orderByes.add(cb.asc(root.get("resType")));
    orderByes.add(cb.asc(root.get("resContent")));

    cq.orderBy(orderByes);

    int maxResults = count.intValue();
    if (maxResults > 0) {
      sc.getPage().setRowCount(maxResults);
      results = em.createQuery(cq)
          .setFirstResult(sc.getPage().getFirstPosition())
          .setMaxResults(sc.getPage().getPageSize())
          .getResultList();
    }

    if (results == null) {
      results = new ArrayList<>();
    }

    return results;
  }

  @Override
  public int deleteRolePrivilege(int enterpriseId, int id) {
    int retCode = 0;

    retCode = em.createQuery(
        "delete from RolePrivilege o where o.id = :id and o.enterpriseId = :enterpriseId")
        .setParameter("id", id)
        .setParameter("enterpriseId", enterpriseId)
        .executeUpdate();

    return retCode;
  }

  @Override
  public int addRolePrivilege(int enterpriseId, String role, Integer[] privilegeIds) {
    int retCode = 0;

    // 已有的角色权限
    List<RolePrivilege> rolePrivileges = em.createQuery("select o from RolePrivilege o " +
        "where o.enterpriseId = :enterpriseId and o.role = :role", RolePrivilege.class)
        .setParameter("enterpriseId", enterpriseId)
        .setParameter("role", role)
        .getResultList();

    for (int privilegeId : privilegeIds) {
      boolean existed = false;
      SysPrivilege sp = em.find(SysPrivilege.class, privilegeId);
      for (RolePrivilege rp : rolePrivileges) {
        if (sp.getResId().equalsIgnoreCase(rp.getResId())) {
          existed = true;
          break;
        }
      }
      if (existed) {
        continue; // 已存在
      }

      // 保存
      RolePrivilege rp = new RolePrivilege();
      rp.setEnterpriseId(enterpriseId);
      rp.setRole(role);
      rp.setResType(sp.getResType());
      rp.setResId(sp.getResId());
      rp.setResContent(sp.getResContent());
      rp.setResRemark(sp.getResRemark());
      em.persist(rp);
      retCode++;
    }

    return retCode;
  }

  @Override
  public List<SysPrivilege> searchPrivileges(int enterpriseId) {
    return em.createQuery("select o from SysPrivilege o order by o.resIndex, o.resType, o.resId",
        SysPrivilege.class)
        .getResultList();
  }

  @Override
  public List<CustomerNote> searchCustomerNotes(final int enterpriseId, CommonSearchCriteria sc,
      final int customerId, final int noteType) {
    List<CustomerNote> results = null;

    CriteriaBuilder cb = em.getCriteriaBuilder();
    CriteriaQuery<CustomerNote> cq = cb.createQuery(CustomerNote.class);
    Root<CustomerNote> root = cq.from(CustomerNote.class);
    root.alias("o");

    var predicates0 = getPredicates_searchCustomerNotes(enterpriseId, customerId, noteType, cb, root);

    //计算根据条件查询得出的数据总数
    CriteriaQuery<Long> countQuery = cb.createQuery(Long.class);
    Root<CustomerNote> countRoot = countQuery.from(CustomerNote.class);
    countRoot.alias("o");

    var predicates1 = getPredicates_searchCustomerNotes(enterpriseId, customerId, noteType, cb, countRoot);

    // count items
    countQuery.select(cb.count(countRoot))
        .where(predicates1.toArray(new Predicate[predicates1.size()]));
    Long count = em.createQuery(countQuery).getSingleResult();

    //查询
    cq.select(root).where(predicates0.toArray(new Predicate[predicates0.size()]));

    List<Order> orderByes = new ArrayList<>();
    orderByes.add(cb.asc(root.get("customer")));
    orderByes.add(cb.asc(root.get("noteType")));
    orderByes.add(cb.asc(root.get("name")));

    cq.orderBy(orderByes);

    int maxResults = count.intValue();
    if (maxResults > 0) {
      sc.getPage().setRowCount(maxResults);
      results = em.createQuery(cq)
          .setFirstResult(sc.getPage().getFirstPosition())
          .setMaxResults(sc.getPage().getPageSize())
          .getResultList();
    }

    if (results == null) {
      results = new ArrayList<>();
    }

    return results;
  }

  private static List<Predicate> getPredicates_searchCustomerNotes(int enterpriseId, int customerId, int noteType, CriteriaBuilder cb, Root<CustomerNote> root) {
    List<Predicate> predicates = new ArrayList<>();

    Predicate predicate = cb.conjunction();
    predicates.add(predicate);

    predicate = cb.equal(root.get(CustomerNote_.enterpriseId), enterpriseId);
    predicates.add(predicate);

    if (customerId > 0) {
      predicate = cb.equal(root.get(CustomerNote_.customer), customerId);
      predicates.add(predicate);
    }

    if (noteType > 0) {
      predicate = cb.equal(root.get(CustomerNote_.noteType), noteType);
      predicates.add(predicate);
    }
    return predicates;
  }

  @Override
  public int createCustomerNote(int enterpriseId, int customerId, int noteType, String name) {
    int retCode = 0;

    Customer customer = em.find(Customer.class, customerId);
    if (customer == null || customer.getEnterpriseId() != enterpriseId) {
      throw new RuntimeException("customer is not existed.");
    }

    CustomerNote note = new CustomerNote();
    note.setEnterpriseId(enterpriseId);
    note.setCustomer(customer);
    note.setNoteType(noteType);
    note.setName(name);

    em.persist(note);

    retCode = note.getId();

    return retCode;
  }

  @Override
  public List<CustomerNote> searchCustomerNotesByType(int enterpriseId, int customerId,
      final int noteType) {

    if (noteType == 0) {
      return em.createQuery("select o from CustomerNote o " +
          " where o.enterpriseId = :enterpriseId " +
              "and o.customer.id = :customerId " +
          " order by o.name", CustomerNote.class)
          .setParameter("enterpriseId", enterpriseId)
          .setParameter("customerId", customerId)
          .getResultList();

    } else {
      return em.createQuery("select o from CustomerNote o " +
          " where o.enterpriseId = :enterpriseId " +
              "and o.customer.id = :customerId " +
              "and o.noteType = :noteType"  +
          " order by o.name", CustomerNote.class)
          .setParameter("enterpriseId", enterpriseId)
          .setParameter("customerId", customerId)
          .setParameter("noteType", noteType)
          .getResultList();
    }
  }

  @Override
  public int deleteCustomerNoteById(int enterpriseId, int id) {
    return em.createQuery("delete from  CustomerNote o " +
        "where o.enterpriseId = :enterpriseId and o.id = :id")
        .setParameter("enterpriseId", enterpriseId)
        .setParameter("id", id)
        .executeUpdate();
  }

  /**
   * 查找需要模拟票号的航司
   */
  @Override
  public List<FakeTicketNo> searchFakedTickets(int enterpriseId, CommonSearchCriteria sc) {
    List<FakeTicketNo> results = null;

    CriteriaBuilder cb = em.getCriteriaBuilder();
    CriteriaQuery<FakeTicketNo> cq = cb.createQuery(FakeTicketNo.class);
    Root<FakeTicketNo> root = cq.from(FakeTicketNo.class);
    root.alias("o");

    var predicates0 = getPredicates_searchFakedTickets(enterpriseId, cb, root);

    //计算根据条件查询得出的数据总数
    CriteriaQuery<Long> countQuery = cb.createQuery(Long.class);
    Root<FakeTicketNo> countRoot = countQuery.from(FakeTicketNo.class);
    countRoot.alias("o");

    var predicates1 = getPredicates_searchFakedTickets(enterpriseId, cb, countRoot);

    // count items
    countQuery.select(cb.count(countRoot))
        .where(predicates1.toArray(new Predicate[predicates1.size()]));
    Long count = em.createQuery(countQuery).getSingleResult();

    //查询
    cq.select(root).where(predicates0.toArray(new Predicate[predicates0.size()]));

    List<Order> orderByes = new ArrayList<>();
    orderByes.add(cb.asc(root.get("twoCode")));

    cq.orderBy(orderByes);

    int maxResults = count.intValue();
    if (maxResults > 0) {
      sc.getPage().setRowCount(maxResults);
      results = em.createQuery(cq)
          .setFirstResult(sc.getPage().getFirstPosition())
          .setMaxResults(sc.getPage().getPageSize())
          .getResultList();
    }

    if (results == null) {
      results = new ArrayList<>();
    }

    return results;
  }

  private static List<Predicate> getPredicates_searchFakedTickets(int enterpriseId, CriteriaBuilder cb, Root<FakeTicketNo> root) {
    List<Predicate> predicates = new ArrayList<>();

    Predicate predicate = cb.conjunction();
    predicates.add(predicate);

    predicate = cb.equal(root.get(FakeTicketNo_.enterpriseId), enterpriseId);
    predicates.add(predicate);
    return predicates;
  }

  @Override
  public int createFakedTicket(FakeTicketNo f) {
    em.persist(f);
    return 1;
  }

  @Override
  public List<EntDepartment> searchEntDepartments(int enterpriseId, CommonSearchCriteria sc) {
    List<EntDepartment> results = null;

    CriteriaBuilder cb = em.getCriteriaBuilder();
    CriteriaQuery<EntDepartment> cq = cb.createQuery(EntDepartment.class);
    Root<EntDepartment> root = cq.from(EntDepartment.class);
    root.alias("o");

    var predicates0 = getPredicates_searchEntDepartments(enterpriseId, cb, root);

    //计算根据条件查询得出的数据总数
    CriteriaQuery<Long> countQuery = cb.createQuery(Long.class);
    Root<EntDepartment> countRoot = countQuery.from(EntDepartment.class);
    countRoot.alias("o");

    var predicates1 = getPredicates_searchEntDepartments(enterpriseId, cb, countRoot);

    // count items
    countQuery.select(cb.count(countRoot))
        .where(predicates1.toArray(new Predicate[predicates1.size()]));
    Long count = em.createQuery(countQuery).getSingleResult();

    //查询
    cq.select(root).where(predicates0.toArray(new Predicate[predicates0.size()]));

    List<Order> orderByes = new ArrayList<>();
    orderByes.add(cb.asc(root.get("deptId")));

    cq.orderBy(orderByes);

    int maxResults = count.intValue();
    if (maxResults > 0) {
      Page page = sc.getPage();
      page.setRowCount(maxResults);

      try {
        results = em.createQuery(cq)
            .setFirstResult(page.getFirstPosition())
            .setMaxResults(page.getPageSize())
            .getResultList();

      } catch (Exception ex) {
        ex.printStackTrace();
      }
    }

    if (results == null) {
      results = new ArrayList<>();
    }

    return results;
  }

  private static List<Predicate> getPredicates_searchEntDepartments(int enterpriseId, CriteriaBuilder cb, Root<EntDepartment> root) {
    List<Predicate> predicates = new ArrayList<>();

    Predicate predicate = cb.conjunction();
    predicates.add(predicate);

    predicate = cb.equal(root.get(EntDepartment_.enterpriseId), enterpriseId);
    predicates.add(predicate);
    return predicates;
  }

  /**
   * 根据企业微信的部门id查询
   */
  @Override
  public List<EntDepartment> searchEntDepartmentByWwDeptId(int enterpriseId, int wwDeptId) {
    return em.createQuery(
        "select o from EntDepartment o where o.enterpriseId = :enterpriseId and o.deptId = :deptId",
        EntDepartment.class)
        .setParameter("enterpriseId", enterpriseId)
        .setParameter("deptId", wwDeptId)
        .getResultList();
  }

  @Override
  public int saveEntDepartment(EntDepartment dept) {
    if (dept.getId() > 0) {
      dept.setLastUpdate(DateUtil.getCurDateTime());
      em.merge(dept);
    } else {
      em.persist(dept);
    }

    return dept.getId();
  }

  @Override
  public EntDepartment getEntDepartment(int id) {
    return em.find(EntDepartment.class, id);
  }

  /**
   * 删除部门
   */
  @Override
  public int deleteEntDepartment(int enterpriseId, int id) {
    return em.createQuery(
        "delete from EntDepartment o where o.enterpriseId = :enterpriseId and o.id = :id")
        .setParameter("enterpriseId", enterpriseId)
        .setParameter("id", id)
        .executeUpdate();
  }


  @Override
  public List<FuelSurcharge> searchFuelSurcharges(int enterpriseId, CommonSearchCriteria sc) {
    List<FuelSurcharge> results = null;

    CriteriaBuilder cb = em.getCriteriaBuilder();
    CriteriaQuery<FuelSurcharge> cq = cb.createQuery(FuelSurcharge.class);
    Root<FuelSurcharge> root = cq.from(FuelSurcharge.class);
    root.alias("o");

    var predicates0 = getPredicates_searchFuelSurcharges(enterpriseId, cb, root);

    //计算根据条件查询得出的数据总数
    CriteriaQuery<Long> countQuery = cb.createQuery(Long.class);
    Root<FuelSurcharge> countRoot = countQuery.from(FuelSurcharge.class);
    countRoot.alias("o");

    var predicates1 = getPredicates_searchFuelSurcharges(enterpriseId, cb, countRoot);

    // count items
    countQuery.select(cb.count(countRoot))
        .where(predicates1.toArray(new Predicate[predicates1.size()]));
    Long count = em.createQuery(countQuery).getSingleResult();

    //查询
    cq.select(root).where(predicates0.toArray(new Predicate[predicates0.size()]));

    List<Order> orderByes = new ArrayList<>();
    orderByes.add(cb.desc(root.get("effectDate")));
    orderByes.add(cb.desc(root.get("mileageType")));

    cq.orderBy(orderByes);

    int maxResults = count.intValue();
    if (maxResults > 0) {
      Page page = sc.getPage();
      page.setRowCount(maxResults);
      int i = (page.getPageNo() - 1) * page.getPageSize();

      if (i < 0) {
        i = 0;
      }

      results = em.createQuery(cq)
          .setFirstResult(i)
          .setMaxResults(page.getPageSize()).getResultList();

    }

    return results == null ? new ArrayList<>() : results;
  }

  private static List<Predicate> getPredicates_searchFuelSurcharges(int enterpriseId, CriteriaBuilder cb, Root<FuelSurcharge> root) {
    List<Predicate> predicates = new ArrayList<>();

    Predicate predicate = cb.conjunction();
    predicates.add(predicate);

    predicate = cb.equal(root.get(FuelSurcharge_.enterpriseId), enterpriseId);
    predicates.add(predicate);
    return predicates;
  }

  /**
   * 保存然后附加费
   */
  @Override
  public int createFuelSurcharge(int enterpriseId, int mileageType, Date effectDate,
      int surcharge) {
    FuelSurcharge info = new FuelSurcharge();
    info.setEnterpriseId(enterpriseId);
    info.setMileageType(mileageType);
    info.setEffectDate(effectDate);
    info.setSurcharge(surcharge);

    em.persist(info);

    return info.getId();
  }

  @Override
  public int deleteFuelSurcharge(int enterpriseId, int id) {
    return em.createQuery(
        "delete from FuelSurcharge o where o.enterpriseId = :enterpriseId and o.id = :id")
        .setParameter("id", id)
        .setParameter("enterpriseId", enterpriseId)
        .executeUpdate();
  }

  @Override
  public Passenger getPassengerById(int enterpriseId, int id) {
    Passenger passenger = em.find(Passenger.class, id);
    if (passenger == null) {
      return null;
    }

    if (passenger.getEnterpriseId() != enterpriseId) {
      return null;
    } else {
      return passenger;
    }
  }

  @Override
  public int deletePassengerInfo(final int userId, final int id) {
    User user = em.find(User.class, userId);
    Passenger passenger = em.find(Passenger.class, id);
    int retCode = em
        .createQuery("delete from Passenger o where o.id = :id and o.enterpriseId = :enterpriseId")
        .setParameter("id", id)
        .setParameter("enterpriseId", user.getEnterpriseId())
        .executeUpdate();
    if (retCode != 1) {
      throw new RuntimeException("Cant delete Passenger(" + id + ").");
    }

    OperationLog log = OperationLog.createLog(user.getEnterpriseId(), OPERATING_OBJECT_BASIC_DATA);
    log.setOperator(user.getUsername());
    log.setContent("删除乘机人信息：" + passenger.toString());
    em.persist(log);

    return retCode;
  }

  @Override
  public EtermEntConfig searchEtermConfig(int enterpriseId) {
    List<EtermEntConfig> cfgs = em
        .createQuery("select o from EtermEntConfig o where o.enterpriseId = :enterpriseId",
            EtermEntConfig.class)
        .setParameter("enterpriseId", enterpriseId)
        .getResultList();
    return cfgs.size() == 1 ? cfgs.get(0) : null;
  }

  @Override
  public AuthCodeInfo getAuthCodeInfo(String authCode) {
    List<AuthCodeInfo> cfgs = em
        .createQuery("select o from AuthCodeInfo o where o.authCode = :authCode",
            AuthCodeInfo.class)
        .setParameter("authCode", authCode)
        .getResultList();
    return cfgs.size() == 1 ? cfgs.get(0) : null;
  }

  @Override
  public int createAuthCodeInfo(String authCode, String mobile, int enterpriseId, String orderType,
      int orderId, String shortUrl) {
    List<AuthCodeInfo> list = em.createQuery("select o from AuthCodeInfo o where o.authCode = :authCode", AuthCodeInfo.class)
            .setParameter("authCode", authCode)
            .getResultList();
    if (!list.isEmpty()) {
      return 0;
    }
    AuthCodeInfo info = new AuthCodeInfo();
    info.setAuthCode(authCode);
    info.setMobile(mobile);
    info.setEnterpriseId(enterpriseId);
    info.setOrderType(orderType);
    info.setOrderId(orderId);
    info.setShortUrl(shortUrl);
    info.setExpiredDate(DateUtil.addDays(DateUtil.getCurDate(), 7));

    em.persist(info);

    return info.getId();
  }

  @Override
  public int setDefaultSupplier(int enterpriseId, int supplierId) {
    //将之前的设置为非默认
    em.createQuery("update Supplier o set o.isDefault = 0 where o.isDefault = 1").executeUpdate();

    //只有综合供应商能设置为默认供应商
    return em.createQuery("update Supplier o set o.isDefault = 1, o.lastUpdate = :lastUpdate " +
        "where o.enterpriseId = :enterpriseId and o.id = :id and o.supplierType = :supplierType")
        .setParameter("id", supplierId)
        .setParameter("enterpriseId", enterpriseId)
        .setParameter("supplierType", 0)
        .setParameter("lastUpdate", DateUtil.getCurDateTime())
        .executeUpdate();
  }

  /**
   * 设置为BSP供应商
   * @param enterpriseId 企业id
   * @param supplierId 供应商id
   */
  @Override
  public int setBspSupplier(final int enterpriseId, final int supplierId, final int bspType) {
    if (bspType != TmsConstant.FLIGHT_AUTO_TICKETING_NONE) {
      //将之前的设置为非默认
      em.createQuery("update Supplier o set o.isBsp = 0 where o.enterpriseId = :enterpriseId and o.isBsp = :isBsp")
              .setParameter("enterpriseId", enterpriseId)
              .setParameter("isBsp", bspType)
              .executeUpdate();
    }

    //只有机票供应商能设置为BSP供应商
    return em.createQuery("update Supplier o set o.isBsp = :isBsp, o.lastUpdate = :lastUpdate " +
        "where o.enterpriseId = :enterpriseId and o.id = :id and o.supplierType = :supplierType")
        .setParameter("id", supplierId)
        .setParameter("enterpriseId", enterpriseId)
        .setParameter("supplierType", SUPPLIER_TYPE_FLIGHT)
        .setParameter("isBsp", bspType)
        .setParameter("lastUpdate", DateUtil.getCurDateTime())
        .executeUpdate();
  }

  @Override
  public List<DataFieldInfo> searchDataFields() {
    return em.createQuery("select o from DataFieldInfo o order by o.dataType, o.id  ",
        DataFieldInfo.class)
        .getResultList();
  }

  @Override
  public int createDataTemplate(DataFieldExportTemplate template) {

    em.persist(template);

    return template.getId();
  }

  @Override
  public DataFieldInfo getDataFieldInfoById(int id) {
    return em.find(DataFieldInfo.class, id);
  }

  @Override
  public List<DataFieldExportTemplate> searchDataTemplates(int enterpriseId,
      CommonSearchCriteria sc) {
    List<DataFieldExportTemplate> results = null;

    CriteriaBuilder cb = em.getCriteriaBuilder();
    CriteriaQuery<DataFieldExportTemplate> cq = cb.createQuery(DataFieldExportTemplate.class);
    Root<DataFieldExportTemplate> root = cq.from(DataFieldExportTemplate.class);
    root.alias("o");

    var predicates0 = getPredicates_searchDataTemplates(enterpriseId, cb, root);

    //计算根据条件查询得出的数据总数
    CriteriaQuery<Long> countQuery = cb.createQuery(Long.class);
    Root<DataFieldExportTemplate> countRoot = countQuery.from(DataFieldExportTemplate.class);
    countRoot.alias("o");

    var predicates1 = getPredicates_searchDataTemplates(enterpriseId, cb, countRoot);

    // count items
    countQuery.select(cb.count(countRoot))
        .where(predicates1.toArray(new Predicate[predicates1.size()]));
    Long count = em.createQuery(countQuery).getSingleResult();

    //查询
    cq.select(root).where(predicates0.toArray(new Predicate[predicates0.size()]));

    List<Order> orderByes = new ArrayList<>();
    orderByes.add(cb.asc(root.get("id")));

    cq.orderBy(orderByes);

    int maxResults = count.intValue();
    if (maxResults > 0) {
      Page page = sc.getPage();
      page.setRowCount(maxResults);
      int i = (page.getPageNo() - 1) * page.getPageSize();

      if (i < 0) {
        i = 0;
      }

      results = em.createQuery(cq)
          .setFirstResult(i)
          .setMaxResults(page.getPageSize()).getResultList();

    }

    return results == null ? new ArrayList<>() : results;
  }

  private static List<Predicate> getPredicates_searchDataTemplates(int enterpriseId, CriteriaBuilder cb, Root<DataFieldExportTemplate> root) {
    List<Predicate> predicates = new ArrayList<>();

    Predicate predicate = cb.conjunction();
    predicates.add(predicate);

    predicate = cb.equal(root.get(DataFieldExportTemplate_.enterpriseId), enterpriseId);
    predicates.add(predicate);
    return predicates;
  }

  @Override
  public List<DataFieldExportTemplate> searchDataTemplates(int enterpriseId) {
    return em.createQuery("select o from DataFieldExportTemplate o where o.enterpriseId = :enterpriseId", DataFieldExportTemplate.class)
        .setParameter("enterpriseId", enterpriseId)
        .getResultList();
  }

  @Override
  public DataFieldExportTemplate searchDataTemplate(int enterpriseId, int templateNo) {
    List<DataFieldExportTemplate> templates = em.createQuery("select o from DataFieldExportTemplate o " +
                    "where o.enterpriseId = :enterpriseId and o.templateNo = :templateNo", DataFieldExportTemplate.class)
        .setParameter("enterpriseId", enterpriseId)
        .setParameter("templateNo", templateNo)
        .getResultList();

    return templates.isEmpty() ? null : templates.get(0);
  }

  @Override
  public int deleteDataTemplateById(int enterpriseId, int id) {
    return em.createQuery(
        "delete from DataFieldExportTemplate  o where o.enterpriseId = :enterpriseId and o.id = :id")
        .setParameter("enterpriseId", enterpriseId)
        .setParameter("id", id)
        .executeUpdate();
  }

  @Override
  public void refreshCustomerRecency() {
    List<Customer> customers = em.createQuery("select o from Customer o", Customer.class).getResultList();
    for(Customer c: customers) {
      final int enterpriseId = c.getEnterpriseId();

      List<FlightOrder> flightOrders = em.createQuery("select o from FlightOrder o " +
              "where o.enterpriseId = :enterpriseId and o.customer.id = :customerId and o.status = :status order by o.id desc", FlightOrder.class)
              .setMaxResults(1)
              .setParameter("enterpriseId", enterpriseId)
              .setParameter("customerId", c.getId())
              .setParameter("status", TmsOrderConstant.FLIGHT_ORDER_STATUS_FINISHED)
              .getResultList();

      if (!flightOrders.isEmpty()) {
        em.createQuery("update Customer o set o.recency = :recency where o.id = :id")
                .setParameter("id", c.getId())
                .setParameter("recency", flightOrders.get(0).getCreateTime())
                .executeUpdate();
      }
    }
  }

  @Override
  public void refreshPassengerRecency(PassengerRecency pr) {
      //更新乘机人购买记录
      List<Passenger> passengers = em.createQuery("select o from Passenger o " +
                      "where o.enterpriseId = :enterpriseId " +
                      "and o.customer.id = :customerId " +
                      "and o.nameCn = :name", Passenger.class)
              .setParameter("enterpriseId", pr.getEnterpriseId())
              .setParameter("customerId", pr.getCustomerId())
              .setParameter("name", pr.getName())
              .getResultList();
      if (passengers.isEmpty()) {
        return;
      }

      for(var p: passengers) {
        String idNo = StringUtils.trimToEmpty(p.getIdNo());
        if (idNo.length() != 18) {
          for(var id: p.getIdInfos()) {
            if (id.getIdType() == ID_TYPE_NI) {
              idNo = StringUtils.trimToEmpty(id.getIdNo());
            }
          }
        }
        if (idNo.length() == 18 && pr.getIdno().equalsIgnoreCase(idNo)) {
          p.setLatestBuyCount(pr.getBuyCount());
          p.setRecency(pr.getRecency());
          p.setLastUpdate(DateUtil.getCurDateTime());

          em.merge(p);
        }
      }
  }

  @Override
  public void refreshSupplierFrequency() {
    final Date beginDate = DateUtil.addMonth(DateUtil.getCurDate(), -3);
    List<Object[]> stats = em.createQuery("select b.enterpriseId, b.supplier, count(b) as billCount " +
            "from BillInfo b " +
            " where b.opDate >= :beginDate " +
            " group by b.enterpriseId, b.supplier order by billCount desc", Object[].class)
            .setParameter("beginDate", beginDate)
            .getResultList();

    for (Object[] stat : stats) {
      final int enterpriseId = (int)stat[0];
      Supplier supplier = (Supplier) stat[1];
      int billCount = ((Long)stat[2]).intValue();
      if (billCount > 10) {
        billCount = (billCount / 10) * 10;
      }

      em.createQuery("update Supplier o set o.frequency = :frequency, o.lastUpdate = :lastUpdate " +
              "where o.enterpriseId = :enterpriseId and o.id = :id")
              .setParameter("enterpriseId", enterpriseId)
              .setParameter("id", supplier.getId())
              .setParameter("frequency", billCount)
              .setParameter("lastUpdate", DateUtil.getCurDateTime())
              .executeUpdate();
    }

  }

  @Override
  public boolean getHideCustomerName(final int enterpriseId) {
    int status = getEnterpriseConfig(enterpriseId, EnterpriseConfig.TMS_HIDE_CUSTOMER_NAME, 0);
    return status == 1;
  }

  @Override
  public boolean isOnlySeeOwn(int enterpriseId) {
    int status = getEnterpriseConfig(enterpriseId, EnterpriseConfig.TMS_OP1_SEE_OWN_ORDER, 0);
    return status == 1;
  }

  @Override
  public List<Integer> searchCustomerEnterpriseId(int ownerId, int mode) {
    if (mode == 0) {
      return em.createQuery("select distinct o.enterpriseId from EnterpriseConfig o " +
              "where o.enterpriseId in (select e.id from Enterprise e where e.parentEnterprise = :ownerId)", Integer.class)
              .setParameter("ownerId", ownerId)
              .getResultList();
    } else if (mode == 1) {
      return em.createQuery("select distinct o.customerEnterpriseId from CustomerFlightDiscount o " +
              "where o.enterpriseId = :ownerId", Integer.class)
              .setParameter("ownerId", ownerId)
              .getResultList();
    } else {
      return new ArrayList<>();
    }
  }

  @Override
  public List<CustomerFlightDiscount> searchCustomerFlightDiscounts(int enterpriseId, int customerEnterpriseId) {
    return em.createQuery("select o from CustomerFlightDiscount o " +
            "where o.enterpriseId = :enterpriseId and o.customerEnterpriseId = :ceid order by o.id", CustomerFlightDiscount.class)
            .setParameter("enterpriseId", enterpriseId)
            .setParameter("ceid", customerEnterpriseId)
            .getResultList();

  }

  @Override
  public int saveCustomerFlightDiscount(CustomerFlightDiscount info) {
    //TODO 记录日志
    em.persist(info);
    return info.getId();
  }

  @Override
  public int deleteCustomerFlightDiscount(int enterpriseId, int customerEnterpriseId, String policyCode) {
    return em.createQuery("delete from CustomerFlightDiscount o " +
            "where o.enterpriseId = :eid and o.customerEnterpriseId = :ceid and o.policyCode = :policyCode")
            .setParameter("eid", enterpriseId)
            .setParameter("ceid", customerEnterpriseId)
            .setParameter("policyCode", policyCode)
            .executeUpdate();
  }

  @Override
  public int createVehicleGroupInfo(int enterpriseId, String username, VehicleGroupInfo info) {
    OperationLog log = OperationLog.createLog(enterpriseId, OPERATING_OBJECT_BASIC_DATA);
    log.setOperator(username);

    if (info.getId() == 0) {
      em.persist(info);
      log.setContent("新建车型组(" + info.getName() + ").");
    } else {
      em.merge(info);
      log.setContent("修改车型组(" + info.getId() + "): " + info.getName() + ", " + info.getLevel());
    }

    em.persist(log);

    return info.getId();
  }

  private List<Predicate> buildPredicates_searchVehicleGroups(CriteriaBuilder cb, Root<VehicleGroupInfo> root, int enterpriseId, CommonSearchCriteria sc) {
    List<Predicate> predicates = new ArrayList<>();

    Predicate predicate = cb.conjunction();
    predicates.add(predicate);

    predicate = cb.equal(root.get(VehicleGroupInfo_.enterpriseId), enterpriseId);
    predicates.add(predicate);

    if (sc.getName() != null && sc.getName().trim().length() > 0) {
      predicate = cb.like(root.get(VehicleGroupInfo_.name), "%" + sc.getName() + "%");
      predicates.add(predicate);
    }

    return predicates;
  }

  @Override
  public List<VehicleGroupInfo> searchVehicleGroups(int enterpriseId, CommonSearchCriteria sc) {
    List<VehicleGroupInfo> results = null;

    CriteriaBuilder cb = em.getCriteriaBuilder();
    CriteriaQuery<VehicleGroupInfo> cq = cb.createQuery(VehicleGroupInfo.class);
    Root<VehicleGroupInfo> root = cq.from(VehicleGroupInfo.class);
    root.alias("o");

    var predicates0 = buildPredicates_searchVehicleGroups(cb, root, enterpriseId, sc);


    //计算根据条件查询得出的数据总数
    CriteriaQuery<Long> countQuery = cb.createQuery(Long.class);
    Root<VehicleGroupInfo> countRoot = countQuery.from(VehicleGroupInfo.class);
    countRoot.alias("o");

    var predicates1 = buildPredicates_searchVehicleGroups(cb, countRoot, enterpriseId, sc);

    // count items
    countQuery.select(cb.count(countRoot))
            .where(predicates1.toArray(new Predicate[predicates1.size()]));
    Long count = em.createQuery(countQuery).getSingleResult();

    //查询
    cq.select(root).where(predicates0.toArray(new Predicate[predicates0.size()]));

    List<Order> orderByes = new ArrayList<>();
    orderByes.add(cb.asc(root.get("id")));

    cq.orderBy(orderByes);

    int maxResults = count.intValue();
    if (maxResults > 0) {
      Page page = sc.getPage();
      page.setRowCount(maxResults);
      int i = (page.getPageNo() - 1) * page.getPageSize();

      if (i < 0) {
        i = 0;
      }

      try {
        results = em.createQuery(cq)
                .setFirstResult(i)
                .setMaxResults(page.getPageSize()).getResultList();

      } catch (Exception ex) {
        ex.printStackTrace();
      }
    }

    return results == null ? new ArrayList<>() : results;
  }

  @Override
  public List<VehicleGroupMapping> searchVehicleGroupMappings(int enterpriseId, List<Integer> ids) {
    return em.createQuery("select o from VehicleGroupMapping o " +
            "where o.enterpriseId = :enterpriseId and o.vehicleGroupInfo.id in :ids", VehicleGroupMapping.class)
            .setParameter("enterpriseId", enterpriseId)
            .setParameter("ids", ids)
            .getResultList();
  }

  @Override
  public VehicleGroupInfo getVehicleGroupInfoById(int id) {
    return em.find(VehicleGroupInfo.class, id);
  }

  @Override
  public int createVehicleGroupMapping(int enterpriseId, String username, VehicleGroupMapping info) {
    info.setEnterpriseId(enterpriseId);

    em.persist(info);

    //TODO 日志

    return info.getId();
  }

  @Override
  public CustomerDepartment getCustomerDepartmentById(int id) {
    return em.find(CustomerDepartment.class, id);
  }

  @Override
  public CustomerDepartment getCustomerDepartmentByDeptId(int enterpriseId, int customerId, int deptId) {
    List<CustomerDepartment> list = em.createQuery("select o from CustomerDepartment o " +
            "where o.enterpriseId = :enterpriseId " +
            "and o.customer.id = :customerId " +
            "and o.departmentNo = :deptId", CustomerDepartment.class)
            .setParameter("enterpriseId", enterpriseId)
            .setParameter("customerId", customerId)
            .setParameter("deptId", deptId)
            .getResultList();
    return list.size() == 1 ? list.get(0) : null;
  }

  @Override
  public CustomerDepartment getCustomerDepartmentByDeptName(int enterpriseId, int customerId, String deptName) {
    List<CustomerDepartment> list = em.createQuery("select o from CustomerDepartment o " +
            "where o.enterpriseId = :enterpriseId " +
            "and o.customer.id = :customerId " +
            "and o.name = :name", CustomerDepartment.class)
            .setParameter("enterpriseId", enterpriseId)
            .setParameter("customerId", customerId)
            .setParameter("name", deptName)
            .getResultList();
    return list.size() == 1 ? list.get(0) : null;
  }

  @Override
  public int saveCustomerPosition(int enterpriseId, String username, CustomerPosition dto) {
    if (dto.getId() == 0) {
      dto.setEnterpriseId(enterpriseId);
      em.persist(dto);
    } else {
      em.merge(dto);
    }

    //TODO 记录日志
    return dto.getId();
  }

  @Override
  public int deleteCustomerPosition(int enterpriseId, String username, int id) {
    return em.createQuery("delete from CustomerPosition o " +
            "where o.enterpriseId = :enterpriseId " +
            "and o.id = :id")
            .setParameter("enterpriseId", enterpriseId)
            .setParameter("id", id)
            .executeUpdate();
  }

  @Override
  public CustomerPosition getCustomerPositionByName(int enterpriseId, int customerId, String positionName) {
    List<CustomerPosition> list = em.createQuery("select o from CustomerPosition o " +
            "where o.enterpriseId = :enterpriseId " +
            "and o.customer.id = :customerId " +
            "and o.name = :name", CustomerPosition.class)
            .setParameter("enterpriseId", enterpriseId)
            .setParameter("customerId", customerId)
            .setParameter("name", positionName)
            .getResultList();
    return list.size() == 1 ? list.get(0) : null;
  }

  @Override
  public int saveApiProductSupplier(int enterpriseId, int productType, int supplierId) {
    ProductDefaultSupplier ps = new ProductDefaultSupplier();
    ps.setEnterpriseId(enterpriseId);
    ps.setProductType(productType);
    Supplier supplier = new Supplier();
    supplier.setId(supplierId);
    ps.setSupplier(supplier);

    em.persist(ps);

    //TODO log

    return ps.getId();
  }

  @Override
  public List<ProductDefaultSupplier> searchApiProductSupplier(int enterpriseId) {
    return em.createQuery("select o from ProductDefaultSupplier o " +
            "where o.enterpriseId = :enterpriseId order by o.productType", ProductDefaultSupplier.class)
            .setParameter("enterpriseId", enterpriseId)
            .getResultList();
  }

  @Override
  public int deleteApiProductSupplier(int enterpriseId, int id) {
    return em.createQuery("delete from ProductDefaultSupplier o " +
            "where o.enterpriseId = :enterpriseId and o.id = :id")
            .setParameter("enterpriseId", enterpriseId)
            .setParameter("id", id)
            .executeUpdate();
  }

  @Override
  public int savePassengers(List<Passenger> passengers) {
    for(Passenger psg: passengers) {
      em.persist(psg);
    }

    return passengers.size();
  }

  @Override
  public ProductDefaultSupplier searchSupplierByApiProduct(final int enterpriseId, final int productType) {
    List<ProductDefaultSupplier> suppliers = em.createQuery("select o from ProductDefaultSupplier o " +
            "where o.enterpriseId = :enterpriseId order by o.productType", ProductDefaultSupplier.class)
            .setParameter("enterpriseId", enterpriseId)
            .getResultList();

    for(ProductDefaultSupplier supplier: suppliers) {
      if (supplier.getProductType() == productType) {
        return supplier;
      }
    }

    return null;
  }

  @Override
  public int createOrUpdateCustomerServiceGroup(int enterpriseId, String username, int id, String code, String name) {
    int retCode = 0;
    GroupCustomerService o;
    if (id > 0) {
      //更新
      o = em.find(GroupCustomerService.class, id);
      o.setGroupName(name.trim().toUpperCase());
      o.setLastUpdate(DateUtil.getCurDateTime());
      em.merge(o);

    } else {
      o = new GroupCustomerService();
      o.setEnterpriseId(enterpriseId);
      o.setGroupCode(code.trim().toUpperCase());
      o.setGroupName(name.trim().toUpperCase());
      em.persist(o);
    }
    retCode = o.getId();

    //日志
    OperationLog log = OperationLog.createLog(enterpriseId, OPERATING_OBJECT_BASIC_DATA);
    log.setOperator(username);
    log.setContent("新建或更新客户服务分组(" + id + ").");
    em.persist(log);

    return retCode;
  }

  @Override
  public List<GroupCustomerService> searchCustomerServiceGroups(int enterpriseId) {
    return em.createQuery("select o from GroupCustomerService o " +
            "where o.enterpriseId = :enterpriseId " +
            "order by o.groupCode", GroupCustomerService.class)
            .setParameter("enterpriseId", enterpriseId)
            .getResultList();
  }

  @Override
  public int updateCustomerGroup(final int enterpriseId, final String username, final int customerId, final int groupId) {
    Customer c = em.find(Customer.class, customerId);
    if (c == null || c.getEnterpriseId() != enterpriseId) {
      throw new RuntimeException("Customer is not existed");
    }

    GroupCustomerService g = em.find(GroupCustomerService.class, groupId);
    if (g == null || g.getEnterpriseId() != enterpriseId) {
      throw new RuntimeException("客户服务分组不存在");
    }

    int retCode = em.createQuery("update Customer o set o.customerServiceGroupCode = :groupCode " +
            "where o.id = :id")
            .setParameter("id", customerId)
            .setParameter("groupCode", g.getGroupCode())
            .executeUpdate();
    if (retCode != 1) {
      throw new RuntimeException("客户服务分组不存在");
    }

    OperationLog log = OperationLog.createLog(enterpriseId, OPERATING_OBJECT_BASIC_DATA);
    log.setOperator(username);
    log.setContent("将客户(" + c.getId() + ", " + c.getVipName() + ")分组到(" + g.getGroupCode() + ", " + g.getGroupName() + ")");
    em.persist(log);

    return customerId;
  }

  @Override
  public GroupCustomerService searchGroupCustomerService(int enterpriseId, String groupCode) {
    List<GroupCustomerService> list = em.createQuery("select o from GroupCustomerService  o " +
            "where o.enterpriseId = :enterpriseId " +
            "and o.groupCode = :groupCode", GroupCustomerService.class)
            .setParameter("enterpriseId", enterpriseId)
            .setParameter("groupCode", groupCode)
            .getResultList();

    return list.size() != 1 ? null :  list.get(0);
  }

  @Override
  public int deleteCustomerGroup(int enterpriseId, String username, int customerId) {
    Customer c = em.find(Customer.class, customerId);
    if (c == null || c.getEnterpriseId() != enterpriseId) {
      throw new RuntimeException("Customer is not existed");
    }

    int retCode = em.createQuery("update Customer o set o.customerServiceGroupCode = null " +
            "where o.id = :id")
            .setParameter("id", customerId)
            .executeUpdate();
    if (retCode != 1) {
      throw new RuntimeException("移除客户服务分组出错");
    }

    OperationLog log = OperationLog.createLog(enterpriseId, OPERATING_OBJECT_BASIC_DATA);
    log.setOperator(username);
    log.setContent("将客户(" + c.getId() + ", " + c.getVipName() + ")移除分组)");
    em.persist(log);

    return customerId;
  }

  @Override
  public int updateRepresentativeGroup(int enterpriseId, String username, int userId, int groupId) {
    User c = em.find(User.class, userId);
    if (c == null || c.getEnterpriseId() != enterpriseId) {
      throw new RuntimeException("User is not existed");
    }

    GroupCustomerService g = em.find(GroupCustomerService.class, groupId);
    if (g == null || g.getEnterpriseId() != enterpriseId) {
      throw new RuntimeException("客户服务分组不存在");
    }

    int retCode = em.createQuery("update User o set o.customerServiceGroupCode = :groupCode " +
            "where o.id = :id")
            .setParameter("id", userId)
            .setParameter("groupCode", g.getGroupCode())
            .executeUpdate();
    if (retCode != 1) {
      throw new RuntimeException("修改客服代表的分组信息时失败");
    }

    OperationLog log = OperationLog.createLog(enterpriseId, OPERATING_OBJECT_BASIC_DATA);
    log.setOperator(username);
    log.setContent("将客服代表(" + c.getUsername() + ", " + c.getEmpname() + ")分组到(" + g.getGroupCode() + ", " + g.getGroupName() + ")");
    em.persist(log);

    return userId;
  }

  @Override
  public int deleteRepresentativeGroup(int enterpriseId, String username, int userId) {
    User c = em.find(User.class, userId);
    if (c == null || c.getEnterpriseId() != enterpriseId) {
      throw new RuntimeException("User is not existed");
    }

    int retCode = em.createQuery("update User o set o.customerServiceGroupCode = null " +
            "where o.id = :id")
            .setParameter("id", userId)
            .executeUpdate();
    if (retCode != 1) {
      throw new RuntimeException("移除客服代表的客户服务分组出错");
    }

    OperationLog log = OperationLog.createLog(enterpriseId, OPERATING_OBJECT_BASIC_DATA);
    log.setOperator(username);
    log.setContent("将客服代表(" + c.getUsername() + ", " + c.getEmpname() + ")移除分组)");
    em.persist(log);

    return userId;
  }

  @Override
  public List<Integer> searchCustomerIdsByGroupCode(int enterpriseId, String groupCode) {
    return em.createQuery("select o.id from Customer o " +
            "where o.enterpriseId = :enterpriseId " +
            "and o.customerServiceGroupCode = :groupCode", Integer.class)
            .setParameter("enterpriseId", enterpriseId)
            .setParameter("groupCode", groupCode)
            .getResultList();
  }

  @Override
  public List<CustomerServiceTemplate> searchCustomerServiceTemplates(int enterpriseId) {
    return em.createQuery("select o from CustomerServiceTemplate o " +
            "where o.enterpriseId = :enterpriseId order by o.templateCode", CustomerServiceTemplate.class)
            .setParameter("enterpriseId", enterpriseId)
            .getResultList();
  }

  @Override
  public int createOrUpdateCustomerServiceTemplate(int enterpriseId, String username, CustomerServiceTemplate tpl) {
    if (tpl.getId() > 0) {
      CustomerServiceTemplate old = em.find(CustomerServiceTemplate.class, tpl.getId());
      if (old == null) {
        throw new RuntimeException("Cannot find the customer service template");
      }

      old.setTemplateName(tpl.getTemplateName());
      old.setFlightPriceMode(tpl.getFlightPriceMode());
      old.setFlightTicketingFee(tpl.getFlightTicketingFee());
      old.setFlightInsurance(tpl.getFlightInsurance());
      old.setFlightRefundFee(tpl.getFlightRefundFee());
      old.setFlightChangeFee(tpl.getFlightChangeFee());
      old.setReportShowFee(tpl.getReportShowFee());
      old.setGpMode(tpl.getGpMode());
      old.setStrength(tpl.getStrength());
      old.setLastUpdate(DateUtil.getCurDateTime());

      em.merge(old);

      //日志
      OperationLog log = OperationLog.createLog(enterpriseId, OPERATING_OBJECT_BASIC_DATA);
      log.setOperator(username);
      log.setContent("更新客户服务费模板(" + tpl.getTemplateCode() + ", " + tpl.getTemplateName()+ ").");
      em.persist(log);

      return old.getId();
    } else {
      em.persist(tpl);

      //日志
      OperationLog log = OperationLog.createLog(enterpriseId, OPERATING_OBJECT_BASIC_DATA);
      log.setOperator(username);
      log.setContent("新建客户服务费模板(" + tpl.getTemplateCode() + ", " + tpl.getTemplateName()+ ").");
      em.persist(log);

      return tpl.getId();
    }
  }

  @Override
  public int updateCustomerTemplate(final int enterpriseId, final String username, final int customerId, final int templateId, String templateCode) {
    Customer c = em.find(Customer.class, customerId);
    if (c == null || c.getEnterpriseId() != enterpriseId) {
      throw new RuntimeException("Customer is not existed");
    }

    CustomerServiceTemplate tpl = null;
    if (templateId > 0) {
      tpl = em.find(CustomerServiceTemplate.class, templateId);
    } else {
      List<CustomerServiceTemplate> list = em.createQuery("select o from CustomerServiceTemplate o " +
              "where o.enterpriseId = :enterpriseId " +
              "and o.templateCode = :code", CustomerServiceTemplate.class)
              .setParameter("enterpriseId", enterpriseId)
              .setParameter("code", templateCode)
              .getResultList();
      tpl = list.isEmpty() ? null : list.get(0);
    }

    if (tpl == null || tpl.getEnterpriseId() != enterpriseId) {
      throw new RuntimeException("客户服务模板不存在");
    }

    int retCode = em.createQuery("update Customer o set o.templateCode = :code " +
            "where o.id = :id")
            .setParameter("id", customerId)
            .setParameter("code", tpl.getTemplateCode())
            .executeUpdate();
    if (retCode != 1) {
      throw new RuntimeException("修改客户服务费模板时出错");
    }

    OperationLog log = OperationLog.createLog(enterpriseId, OPERATING_OBJECT_BASIC_DATA);
    log.setOperator(username);
    log.setContent("为客户(" + c.getId() + ", " + c.getVipName() + ")应用服务费模板(" + tpl.getTemplateCode() + ", " + tpl.getTemplateName() + ")");
    em.persist(log);

    return customerId;
  }

  @Override
  public CustomerServiceTemplate searchCustomerServiceTemplate(int enterpriseId, String templateCode) {
    List<CustomerServiceTemplate> list = em.createQuery("select o from CustomerServiceTemplate o " +
            "where o.enterpriseId = :enterpriseId " +
            "and o.templateCode = :code", CustomerServiceTemplate.class)
            .setParameter("enterpriseId", enterpriseId)
            .setParameter("code", templateCode)
            .getResultList();

    return list.isEmpty() ? null : list.get(0);
  }

  @Override
  public CustomerServiceTemplate searchServiceTemplateByCustomer(int enterpriseId, int customerId) {
    Customer c = em.find(Customer.class, customerId);
    if (c == null
            || c.getEnterpriseId() != enterpriseId
            || c.getTemplateCode() == null
            || c.getTemplateCode().trim().length() == 0) {
      return null;
    }

    List<CustomerServiceTemplate> tpls = em.createQuery("select o from CustomerServiceTemplate o " +
            "where o.enterpriseId = :enterpriseId and o.templateCode = :code", CustomerServiceTemplate.class)
            .setParameter("enterpriseId", enterpriseId)
            .setParameter("code", c.getTemplateCode())
            .getResultList();

    return tpls.isEmpty() ? null : tpls.get(0);
  }

  @Override
  public int saveBlobMapping(int enterpriseId, String username, String fileName, String blobName, String contentType, long fileSize) {
    AzureStorageFileNameMapping fm = new AzureStorageFileNameMapping();
    fm.setEnterpriseId(enterpriseId);
    fm.setUsername(username);
    fm.setFileName(fileName);
    fm.setBlobName(blobName);
    fm.setContentType(contentType);
    fm.setFileSize(fileSize);

    em.persist(fm);

    return fm.getId();
  }

  @Override
  public AzureStorageFileNameMapping getBlobMappingById(int id) {
    return em.find(AzureStorageFileNameMapping.class, id);
  }

  @Override
  public int disableSupplier(int enterpriseId, int id, String username, String remark) {
    int retCode = em.createQuery("update Supplier o " +
            "set o.status = 0, o.lastUpdate = :lastUpdate " +
            "where " +
            "o.id = :id " +
            "and o.enterpriseId = :enterpriseId " +
            "and (o.status = 1 or o.status is null)")
            .setParameter("id", id)
            .setParameter("enterpriseId", enterpriseId)
            .setParameter("lastUpdate", DateUtil.getCurDateTime())
            .executeUpdate();
    if (retCode != 1) {
      throw new RuntimeException("Failed to disable Supplier.");
    }

    OperationLog log = OperationLog.createLog(enterpriseId, OPERATING_OBJECT_BASIC_DATA);
    log.setOperator(username);
    log.setContent(remark);
    em.persist(log);

    return log.getId();
  }

  @Override
  public List<Supplier> searchSupplierByTicketingType(int enterpriseId, int ticketingType) {
    return em.createQuery("select o from Supplier o " +
            "where o.enterpriseId = :enterpriseId and o.isBsp = :ticketingType", Supplier.class)
            .setParameter("enterpriseId", enterpriseId)
            .setParameter("ticketingType", ticketingType)
            .getResultList();
  }

  @Override
  public List<TmsTask> searchTasks(int enterpriseId, CommonSearchCriteria sc) {
    List<TmsTask> results = null;

    CriteriaBuilder cb = em.getCriteriaBuilder();
    CriteriaQuery<TmsTask> cq = cb.createQuery(TmsTask.class);
    Root<TmsTask> root = cq.from(TmsTask.class);
    root.alias("o");

    var predicates0 = getPredicates_searchTasks(enterpriseId, sc, cb, root);

    //计算根据条件查询得出的数据总数
    CriteriaQuery<Long> countQuery = cb.createQuery(Long.class);
    Root<TmsTask> countRoot = countQuery.from(TmsTask.class);
    countRoot.alias("o");

    var predicates1 = getPredicates_searchTasks(enterpriseId, sc, cb, countRoot);

    // count items
    countQuery.select(cb.count(countRoot))
            .where(predicates1.toArray(new Predicate[predicates1.size()]));
    Long count = em.createQuery(countQuery).getSingleResult();

    //查询
    cq.select(root).where(predicates0.toArray(new Predicate[predicates0.size()]));

    List<Order> orderByes = new ArrayList<>();
    orderByes.add(cb.desc(root.get("id")));

    cq.orderBy(orderByes);

    int maxResults = count.intValue();
    if (maxResults > 0) {
      Page page = sc.getPage();
      page.setRowCount(maxResults);

      try {
        results = em.createQuery(cq)
                .setFirstResult(page.getFirstPosition())
                .setMaxResults(page.getPageSize())
                .getResultList();

      } catch (Exception ex) {
        ex.printStackTrace();
      }
    }

    if (results == null) {
      results = new ArrayList<>();
    }

    return results;
  }

  private static List<Predicate> getPredicates_searchTasks(int enterpriseId, CommonSearchCriteria sc, CriteriaBuilder cb, Root<TmsTask> root) {
    List<Predicate> predicates = new ArrayList<>();

    Predicate predicate = cb.conjunction();
    predicates.add(predicate);

    predicate = cb.equal(root.get(TmsTask_.enterpriseId), enterpriseId);
    predicates.add(predicate);

    if (sc.getType() > -1) {
      predicate = cb.equal(root.get(TmsTask_.taskType), sc.getType());
      predicates.add(predicate);
    }
    return predicates;
  }

  @Override
  public List<TmsTask> searchTasks(int enterpriseId, int taskType, Date taskDate) {
    return em.createQuery("select o from TmsTask o " +
            "where o.enterpriseId = :enterpriseId " +
            "and o.taskType = :taskType " +
            "and o.createDate = :createDate", TmsTask.class)
            .setParameter("enterpriseId", enterpriseId)
            .setParameter("taskType", taskType)
            .setParameter("createDate", taskDate)
            .getResultList();
  }

  @Override
  public int finishDailyTask(int enterpriseId, String username, int taskId) {
    int retCode = em.createQuery("update TmsTask o set o.status = 1, o.doneDate = :doneDate " +
            "where o.id = :id and o.enterpriseId = :enterpriseId and (o.status is null or o.status = 0)")
            .setParameter("id", taskId)
            .setParameter("enterpriseId", enterpriseId)
            .setParameter("doneDate", DateUtil.getCurDateTime())
            .executeUpdate();
    if (retCode == 1) {
      OperationLog log = OperationLog.createLog(enterpriseId, OPERATING_OBJECT_TMS_TASK);
      log.setEnterpriseId(enterpriseId);
      log.setOperator(username);
      log.setContent("完成每日任务(" + taskId + ")");
      log.setOrderId(taskId);
      em.persist(log);

    }

    return retCode;
  }

  @Override
  public void updateDailyTaskSendFileTime(int enterpriseId, String username, int taskId) {
    int retCode = em.createQuery("update TmsTask o set o.sendFileTime = :sendDate " +
            "where o.id = :id and o.enterpriseId = :enterpriseId")
            .setParameter("id", taskId)
            .setParameter("enterpriseId", enterpriseId)
            .setParameter("sendDate", DateUtil.getCurDateTime())
            .executeUpdate();
    if (retCode == 1) {
      OperationLog log = OperationLog.createLog(enterpriseId, OPERATING_OBJECT_TMS_TASK);
      log.setEnterpriseId(enterpriseId);
      log.setOperator(username);
      log.setContent("完成任务(" + taskId + ")的文件发送。");
      log.setOrderId(taskId);
      em.persist(log);

    }

  }

  @Override
  public List<ReportTemplateInfo> searchReportTemplates(int enterpriseId) {
    //TODO 规划：根据不同的客户开通不同的报表模板
    return em.createQuery("select o from ReportTemplateInfo o order by o.name", ReportTemplateInfo.class)
            .getResultList();
  }

  @Override
  public int updateCustomerReportTemplate(int enterpriseId, String username, int customerId, int templateId) {
    Customer c = em.find(Customer.class, customerId);
    if (c == null || c.getEnterpriseId() != enterpriseId) {
      throw new RuntimeException("Customer is not existed");
    }

    ReportTemplateInfo g = em.find(ReportTemplateInfo.class, templateId);
    if (g == null) {
      throw new RuntimeException("报表模板不存在");
    }

    int retCode = em.createQuery("update Customer o set o.reportTemplateId = :tplId " +
            "where o.id = :id")
            .setParameter("id", customerId)
            .setParameter("tplId", templateId)
            .executeUpdate();
    if (retCode != 1) {
      throw new RuntimeException("报表模板不存在");
    }

    OperationLog log = OperationLog.createLog(enterpriseId, OPERATING_OBJECT_BASIC_DATA);
    log.setOperator(username);
    log.setContent("将客户(" + c.getId() + ", " + c.getVipName() + ")的报表模板修改为(" + g.getId() + ", " + g.getName() + ")");
    em.persist(log);

    return customerId;
  }


  @Override
  public List<PassengerFlightPolicy> searchPassengerFlightPolicies(int enterpriseId, int psgId) {
    return em.createQuery("select o from PassengerFlightPolicy o " +
            "where o.enterpriseId = :enterpriseId " +
            "and o.passenger.id = :psgId " +
            "order by o.policyInfo.id", PassengerFlightPolicy.class)
            .setParameter("enterpriseId", enterpriseId)
            .setParameter("psgId", psgId)
            .getResultList();
  }

  @Override
  public List<TmsWwAppChat> searchWwAppChats(int enterpriseId) {
    return em.createQuery("select o from TmsWwAppChat o " +
            "where o.enterpriseId = :enterpriseId " +
            "order by o.id", TmsWwAppChat.class)
            .setParameter("enterpriseId", enterpriseId)
            .getResultList();
  }

  @Override
  public int createWwAppChat(TmsWwAppChat appChat) {
    em.persist(appChat);
    return appChat.getId();
  }

  @Override
  public void updateWwAppChat(TmsWwAppChat appChat) {
    appChat.setLastUpdate(DateUtil.getCurDateTime());
    em.merge(appChat);
  }

  @Override
  public List<TmsWwUser> searchWwUsers(int enterpriseId) {
    return em.createQuery("select o from TmsWwUser o " +
            "where o.enterpriseId = :enterpriseId " +
            "order by o.id", TmsWwUser.class)
            .setParameter("enterpriseId", enterpriseId)
            .getResultList();
  }

  @Override
  public TmsWwAppChat searchWwAppChat(int enterpriseId, String chatId) {
    var list = em.createQuery("select o from TmsWwAppChat o " +
            "where o.enterpriseId = :enterpriseId and o.chatId = :chatId " +
            "order by o.id", TmsWwAppChat.class)
            .setParameter("enterpriseId", enterpriseId)
            .setParameter("chatId", chatId)
            .getResultList();
    return list.size() == 1 ? list.get(0): null;
  }

  @Override
  public TmsWwAppChat searchWwAppChatByType(int enterpriseId, String chatType) {
    var list = em.createQuery("select o from TmsWwAppChat o " +
            "where o.enterpriseId = :enterpriseId and o.chatType = :chatType " +
            "order by o.id desc", TmsWwAppChat.class)
            .setParameter("enterpriseId", enterpriseId)
            .setParameter("chatType", chatType)
            .setMaxResults(1)
            .getResultList();
    return list.isEmpty() ? null: list.get(0);
  }

  @Override
  public int updateAlipayConfig(int enterpriseId, String username, String mainAccount, String appId, String privateKey,
                                String alipayPublicKey, String returnUrl, String notifyUrl) {
    var list = em.createQuery("select o from EntAlipayConfig o " +
                    "where o.enterpriseId = :enterpriseId " +
                    "and o.mainAccount = :mainAccount " +
                    "and o.appId = :appId", EntAlipayConfig.class)
            .setParameter("enterpriseId", enterpriseId)
            .setParameter("mainAccount", mainAccount)
            .setParameter("appId", appId)
            .getResultList();
    if (list.isEmpty()) {
      var cfg = new EntAlipayConfig();
      cfg.setEnterpriseId(enterpriseId);
      cfg.setMainAccount(mainAccount);
      cfg.setAppId(appId);
      cfg.setPrivateKey(privateKey);
      cfg.setAlipayPublicKey(alipayPublicKey);
      cfg.setReturnUrl(returnUrl);
      cfg.setNotifyUrl(notifyUrl);
      em.persist(cfg);
      return cfg.getId();
    } else {
      var cfg = list.get(0);
      if (StringUtils.isNotBlank(privateKey)) {
        cfg.setPrivateKey(privateKey);
      }
      if (StringUtils.isNotBlank(alipayPublicKey)) {
        cfg.setAlipayPublicKey(alipayPublicKey);
      }
      cfg.setReturnUrl(returnUrl);
      cfg.setNotifyUrl(notifyUrl);
      em.merge(cfg);
      return cfg.getId();
    }
  }

  @Override
  public List<EntAlipayConfig> searchAlipayConfigs(int enterpriseId) {
    return  em.createQuery("select o from EntAlipayConfig o " +
                    "where o.enterpriseId = :enterpriseId order by o.id", EntAlipayConfig.class)
            .setParameter("enterpriseId", enterpriseId)
            .getResultList();
  }

  @Override
  public int deleteAlipayConfig(int enterpriseId, String username, int id) {
    var cfg = em.find(EntAlipayConfig.class, id);
    if (cfg == null) {
      return -1;
    }

    em.remove(cfg);

    var log = OperationLog.createLog(enterpriseId, OPERATING_OBJECT_BASIC_DATA);
    log.setOperator(username);
    log.setContent("删除 支付宝参数(" + cfg.getMainAccount() + ", " + cfg.getAppId() + ")");
    em.persist(log);

    return cfg.getId();
  }

  @Override
  public List<EntEotmsConfig> searchEntEotmsConfig(int enterpriseId) {
    return em.createQuery("select o from EntEotmsConfig o " +
                    "where o.enterpriseId = :enterpriseId", EntEotmsConfig.class)
            .setParameter("enterpriseId", enterpriseId)
            .getResultList();
  }

  @Override
  public CustomerServiceTemplate getCustomerServiceTemplateById(int enterpriseId, int id) {
    CustomerServiceTemplate tpl = em.find(CustomerServiceTemplate.class, id);
    if (tpl == null || tpl.getEnterpriseId() != enterpriseId) {
      return null;
    }

    return tpl;
  }

  @Override
  public List<CustomerServiceFlightRule> searchCustomerServiceFlightRules(int enterpriseId, String templateCode) {
    return em.createQuery("select o from CustomerServiceFlightRule o " +
            "where o.enterpriseId = :enterpriseId " +
            "and o.templateCode = :templateCode order by o.carrier", CustomerServiceFlightRule.class)
            .setParameter("enterpriseId", enterpriseId)
            .setParameter("templateCode", templateCode)
            .getResultList();
  }

  @Override
  public int createOrUpdateCustomerServiceFlightRule(int enterpriseId, String username, String templateCode, CustomerServiceFlightRule fltRule) {
    List<CustomerServiceFlightRule> flightRules = em.createQuery("select o from CustomerServiceFlightRule o " +
            "where o.enterpriseId = :enterpriseId " +
            "and o.templateCode = :templateCode " +
            "and o.carrier = :carrier", CustomerServiceFlightRule.class)
            .setParameter("enterpriseId", enterpriseId)
            .setParameter("templateCode", templateCode)
            .setParameter("carrier", fltRule.getCarrier())
            .getResultList();
    if (flightRules.isEmpty()) {
      fltRule.setId(0);
      fltRule.setEnterpriseId(enterpriseId);
      fltRule.setTemplateCode(templateCode);
      em.persist(fltRule);
    } else {
      CustomerServiceFlightRule old = flightRules.get(0);
      old.setCarrier(fltRule.getCarrier());
      old.setSubclasses(fltRule.getSubclasses());
      old.setFlightTicketingFee(fltRule.getFlightTicketingFee());
      old.setFlightRefundFee(fltRule.getFlightRefundFee());
      old.setFlightChangeFee(fltRule.getFlightChangeFee());
      old.setLastUpdate(DateUtil.getCurDateTime());
      em.merge(old);

      fltRule.setId(old.getId());
    }

    OperationLog log = OperationLog.createLog(enterpriseId, OPERATING_OBJECT_BASIC_DATA);
    log.setOperator(username);
    log.setContent("保存客服服务模板(" + templateCode + ")的机票特定规则: "
            + fltRule.getCarrier() + "<" + fltRule.getSubclasses()+ ">, "
            + fltRule.getFlightTicketingFee() + ", "
            + fltRule.getFlightRefundFee() + ", "
            + fltRule.getFlightChangeFee() + ".");
    em.persist(log);

    return fltRule.getId();

  }


  @Override
  public List<PnrTourCode> searchTourCodes(int enterpriseId) {
    return em.createQuery("select o from PnrTourCode o where o.enterpriseId = :enterpriseId ",
        PnrTourCode.class)
        .setParameter("enterpriseId", enterpriseId)
        .getResultList();
  }

  @Override
  public int createPnrTourCode(PnrTourCode pnrTourCode) {
    em.persist(pnrTourCode);
    return pnrTourCode.getId();
  }

  @Override
  public int updatePnrTourCode(PnrTourCode pnrTourCode) {
    pnrTourCode.setLastUpdate(DateUtil.getCurDateTime());
    em.merge(pnrTourCode);
    return pnrTourCode.getId();
  }

  @Override
  public int saveEtermConfig(int enterpriseId, String host, int port, String username,
      String password) {
    EtermEntConfig old = this.searchEtermConfig(enterpriseId);
    if (old == null) {
      EtermEntConfig config = new EtermEntConfig();
      config.setEnterpriseId(enterpriseId);
      config.setHost(host);
      config.setPort(port);
      config.setUsername(username);
      config.setPassword(password);
      config.setMaxConnection(1);

      em.persist(config);

      return config.getId();
    } else {
      old.setHost(host);
      old.setPort(port);
      old.setUsername(username);
      old.setPassword(password);
      old.setLastUpdate(DateUtil.getCurDateTime());

      em.merge(old);

      return old.getId();
    }
  }

  private String doGetItemValue(int enterpriseId, String itemCode) {
    List<EnterpriseConfig> configs = em.createQuery("select o from EnterpriseConfig o " +
        "where o.enterpriseId = :enterpriseId and o.itemCode = :itemCode", EnterpriseConfig.class)
        .setParameter("enterpriseId", enterpriseId)
        .setParameter("itemCode", itemCode)
        .getResultList();

    return configs.size() == 1 ? configs.get(0).getItemValue().trim() : "";
  }

  private int doSetItemValue(final int enterpriseId, final String itemCode, final String itemValue) {
    int retCode = em.createQuery("update EnterpriseConfig o " +
            "set o.itemValue = :itemValue, o.lastUpdate = :lastUpdate " +
                    "where o.enterpriseId = :enterpriseId and o.itemCode = :itemCode")
            .setParameter("enterpriseId", enterpriseId)
            .setParameter("itemCode", itemCode)
            .setParameter("itemValue", itemValue)
            .setParameter("lastUpdate", DateUtil.getCurDateTime())
            .executeUpdate();

    if (retCode == 0) {
      EnterpriseConfig ec = new EnterpriseConfig();
      ec.setEnterpriseId(enterpriseId);
      ec.setItemCode(itemCode);
      ec.setItemValue(itemValue);
      em.persist(ec);

      retCode = ec.getId();
    }

    OperationLog log = OperationLog.createLog(enterpriseId, OPERATING_OBJECT_BASIC_DATA);
    log.setContent("更新企业参数(" + itemCode + "): " + itemValue);
    em.persist(log);

    return retCode;
  }

}
